home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 176-200 / disk_195 / microemacs / src.zoo / amigados.c next >
C/C++ Source or Header  |  1989-03-23  |  20KB  |  861 lines

  1. /*    AMIGADOS.C:    Operating specific I/O and Spawning functions
  2.             for MicroEMACS 3.10
  3.             (C)opyright 1988 by Daniel M. Lawrence
  4. */
  5.  
  6. #include        <stdio.h>
  7. #include    "estruct.h"
  8. #if    AMIGA
  9. #include    <exec/types.h>
  10. #include    <exec/io.h>
  11. #include    <intuition/intuition.h>
  12. #include    <devices/console.h>
  13. #include    "etype.h"
  14. #include        "edef.h"
  15. #include    "elang.h"
  16.  
  17. #define INTUITION_REV    0L
  18. #define    NEW         1006L
  19. #define    CRWIDTH        8
  20. #define    CRHEIGHT    8
  21.  
  22. struct IntuitionBase *IntuitionBase;
  23. struct Window *win;
  24. struct IOStdReq con;        /* ptr to console device driver handle */
  25.  
  26. /*    Intuition Function type declarations    */
  27.  
  28. struct IntuitionBase *OpenLibrary();
  29. struct Window *OpenWindow();
  30. struct IntuiMessage *GetMsg();
  31.  
  32. typedef struct {
  33.     short rw_code;        /* normal keycode to generate */
  34.     short rw_scode;        /* shifted  "  */
  35.     short rw_ccode;        /* control  "  */
  36. } RKEY;
  37.  
  38. /* raw keycode scan code to emacs keycode translation table */
  39.  
  40. RKEY keytrans[0x60] = {
  41.  
  42. /*    CODE    NORM    SHIFT    CTRL */
  43. /*    0x00,*/    '`',    '~',    0,
  44. /*    0x01,*/    '1',    '!',    0,
  45. /*    0x02,*/    '2',    '@',    0,
  46. /*    0x03,*/    '3',    '#',    0,
  47. /*    0x04,*/    '4',    '$',    0,
  48. /*    0x05,*/    '5',    '%',    0,
  49. /*    0x06,*/    '6',    '^',    0,
  50. /*    0x07,*/    '7',    '&',    0,
  51. /*    0x08,*/    '8',    '*',    0,    
  52. /*    0x09,*/    '9',    '(',    0,
  53. /*    0x0a,*/    '0',    ')',    0,
  54. /*    0x0b,*/    '-',    '_',    0,
  55. /*    0x0c,*/    '=',    '+',    0,
  56. /*    0x0d,*/    '\\',    '|',    0,
  57. /*    0x0e,*/    0,    0,    0,
  58. /*    0x0f,*/    0,    0,    0,
  59. /*    0x10,*/    'q',    'Q',    CTRL|'Q',
  60. /*    0x11,*/    'w',    'W',    CTRL|'W',
  61. /*    0x12,*/    'e',    'E',    CTRL|'E',
  62. /*    0x13,*/    'r',    'R',    CTRL|'R',
  63. /*    0x14,*/    't',    'T',    CTRL|'T',
  64. /*    0x15,*/    'y',    'Y',    CTRL|'Y',
  65. /*    0x16,*/    'u',    'U',    CTRL|'U',
  66. /*    0x17,*/    'i',    'I',    CTRL|'I',
  67. /*    0x18,*/    'o',    'O',    CTRL|'O',
  68. /*    0x19,*/    'p',    'P',    CTRL|'P',
  69. /*    0x1a,*/    '[',    '{',    0,
  70. /*    0x1b,*/    ']',    '}',    0,
  71. /*    0x1c,*/    0,    0,    0,
  72. /*    0x1d,*/    '1',    SPEC|'>',    0,
  73. /*    0x1e,*/    '2',    SPEC|'N',    0,
  74. /*    0x1f,*/    '3',    SPEC|'V',    0,
  75. /*    0x20,*/    'a',    'A',    CTRL|'A',
  76. /*    0x21,*/    's',    'S',    CTRL|'S',
  77. /*    0x22,*/    'd',    'D',    CTRL|'D',
  78. /*    0x23,*/    'f',    'F',    CTRL|'F',
  79. /*    0x24,*/    'g',    'G',    CTRL|'G',
  80. /*    0x25,*/    'h',    'H',    CTRL|'H',
  81. /*    0x26,*/    'j',    'J',    CTRL|'J',
  82. /*    0x27,*/    'k',    'K',    CTRL|'K',
  83. /*    0x28,*/    'l',    'L',    CTRL|'L',
  84. /*    0x29,*/    ';',    ':',    0,
  85. /*    0x2a,*/    39,    34,    0,
  86. /*    0x2b,*/    0,    0,    0,
  87. /*    0x2c,*/    0,    0,    0,
  88. /*    0x2d,*/    '4',    SPEC|'B',    0,
  89. /*    0x2e,*/    '5',    0,        0,
  90. /*    0x2f,*/    '6',    SPEC|'F',    0,
  91.     /* this key is probably mapped on forign AIMIGA keyboards */
  92. /*    0x30,*/    0,    0,    0,
  93. /*    0x31,*/    'z',    'Z',    CTRL|'Z',
  94. /*    0x32,*/    'x',    'X',    CTRL|'X',
  95. /*    0x33,*/    'c',    'C',    CTRL|'C',
  96. /*    0x34,*/    'v',    'V',    CTRL|'V',
  97. /*    0x35,*/    'b',    'B',    CTRL|'B',
  98. /*    0x36,*/    'n',    'N',    CTRL|'N',
  99. /*    0x37,*/    'm',    'M',    CTRL|'M',
  100. /*    0x38,*/    ',',    '<',    0,
  101. /*    0x39,*/    '.',    '>',    0,
  102. /*    0x3a,*/    '/',    '?',    0,
  103. /*    0x3b,*/    0,    0,    0,
  104. /*    0x3c,*/    '.',    SPEC|'D',    0,
  105. /*    0x3d,*/    '7',    SPEC|'<',    0,
  106. /*    0x3e,*/    '8',    SPEC|'P',    0,
  107. /*    0x3f,*/    '9',    SPEC|'Z',    0,
  108. /*    0x40,*/    ' ',    SHFT|' ',    0,
  109. /*    0x41,*/    CTRL|'H',    SHFT|'D',    0,
  110. /*    0x42,*/    CTRL|'I',    SHFT|'I',    0,
  111. /*    0x43,*/    CTRL|'M', CTRL|'M', CTRL|'M',
  112. /*    0x44,*/    CTRL|'M', CTRL|'M', CTRL|'M',
  113. /*    0x45,*/    CTRL|'[',    0,    0,
  114. /*    0x46,*/    SPEC|'D',    0,    0,
  115. /*    0x47,*/    0,    0,    0,
  116. /*    0x48,*/    0,    0,    0,
  117. /*    0x49,*/    0,    0,    0,
  118. /*    0x4a,*/    '-',    0,    0,
  119. /*    0x4b,*/    0,    0,    0,
  120. /*    0x4c,*/    SPEC|'P',    SHFT|SPEC|'P',    CTRL|SPEC|'P',
  121. /*    0x4d,*/    SPEC|'N',    SHFT|SPEC|'N',    CTRL|SPEC|'N',
  122. /*    0x4e,*/    SPEC|'F',    SHFT|SPEC|'F',    CTRL|SPEC|'F',
  123. /*    0x4f,*/    SPEC|'B',    SHFT|SPEC|'B',    CTRL|SPEC|'B',
  124. /*    0x50,*/    SPEC|'1',    SHFT|SPEC|'1',    CTRL|SPEC|'1',
  125. /*    0x51,*/    SPEC|'2',    SHFT|SPEC|'2',    CTRL|SPEC|'2',
  126. /*    0x52,*/    SPEC|'3',    SHFT|SPEC|'3',    CTRL|SPEC|'3',
  127. /*    0x53,*/    SPEC|'4',    SHFT|SPEC|'4',    CTRL|SPEC|'4',
  128. /*    0x54,*/    SPEC|'5',    SHFT|SPEC|'5',    CTRL|SPEC|'5',
  129. /*    0x55,*/    SPEC|'6',    SHFT|SPEC|'6',    CTRL|SPEC|'6',
  130. /*    0x56,*/    SPEC|'7',    SHFT|SPEC|'7',    CTRL|SPEC|'7',
  131. /*    0x57,*/    SPEC|'8',    SHFT|SPEC|'8',    CTRL|SPEC|'8',
  132. /*    0x58,*/    SPEC|'9',    SHFT|SPEC|'9',    CTRL|SPEC|'9',
  133. /*    0x59,*/    SPEC|'0',    SHFT|SPEC|'0',    CTRL|SPEC|'0',
  134. /*    0x5a,*/    '(',    0,    0,
  135. /*    0x5b,*/    ')',    0,    0,
  136. /*    0x5c,*/    '/',    0,    0,
  137. /*    0x5d,*/    '*',    0,    0,
  138. /*    0x5e,*/    0,    0,    0,
  139. /*    0x5f,*/    SPEC|'?',    0,    0,
  140. };
  141.  
  142. /* some keyboard keys current states */
  143.  
  144. int r_shiftflag;    /* right shift key */
  145. int l_shiftflag;    /* left shift key */
  146. int r_altflag;        /* right alt key */
  147. int l_altflag;        /* left alt key */
  148. int r_amiflag;        /* right amiga key */
  149. int l_amiflag;        /* left amiga key */
  150. int ctrlflag;        /* control key */
  151. int lockflag;        /* shift lock key */
  152.  
  153. /*    output buffers and pointers    */
  154.  
  155. #define OBUFSIZE    1024L
  156. #define    IBUFSIZE    64    /* this must be a power of 2 */
  157.  
  158. char out_buf[OBUFSIZE+1];    /* output character buffer */
  159. int out_ptr = 0;        /* index to next char to put in buffer */
  160.  
  161. /*    input buffers and pointers    */
  162.  
  163. #define    IBUFSIZE    64    /* this must be a power of 2 */
  164.  
  165. unsigned char in_buf[IBUFSIZE];    /* input character buffer */
  166. int in_next = 0;        /* pos to retrieve next input character */
  167. int in_last = 0;        /* pos to place most recent input character */
  168.  
  169. in_init()    /* initialize the input buffer */
  170.  
  171. {
  172.     in_next = in_last = 0;
  173. }
  174.  
  175. in_check()    /* is the input buffer non-empty? */
  176.  
  177. {
  178.     if (in_next == in_last)
  179.         return(FALSE);
  180.     else
  181.         return(TRUE);
  182. }
  183.  
  184. in_put(event)
  185.  
  186. int event;    /* event to enter into the input buffer */
  187.  
  188. {
  189.     in_buf[in_last++] = event;
  190.     in_last &= (IBUFSIZE - 1);
  191. }
  192.  
  193. int in_get()    /* get an event from the input buffer */
  194.  
  195. {
  196.     register int event;    /* event to return */
  197.  
  198.     event = in_buf[in_next++];
  199.     in_next &= (IBUFSIZE - 1);
  200.     return(event);
  201. }
  202.  
  203. /*
  204.  * This function is called once to set up the terminal device streams.
  205.  * On VMS, it translates TT until it finds the terminal, then assigns
  206.  * a channel to it and sets it raw. On CPM it is a no-op.
  207.  */
  208. ttopen()
  209. {
  210.     struct NewWindow new_win;
  211.     int i;
  212. #if    AZTEC
  213.     extern    Enable_Abort;    /* Turn off ctrl-C interrupt */
  214.  
  215.     Enable_Abort = 0;    /* for the Manx compiler */
  216. #endif
  217.  
  218.     /* open the intuition library */
  219.     IntuitionBase = (struct IntuitionBase *)
  220.         OpenLibrary("intuition.library", INTUITION_REV);
  221.     if (IntuitionBase == NULL) {
  222.         printf("%%Can not open Intuition\n");
  223.         exit(-1);
  224.     }
  225.  
  226.     /* initialize the new windows attributes */
  227.     new_win.LeftEdge = 0;
  228.     new_win.TopEdge = 0;
  229.     new_win.Width = 640;
  230.     new_win.Height = 200;
  231.     new_win.DetailPen = 0;
  232.     new_win.BlockPen = 1;
  233.     new_win.Title = (unsigned char *)"MicroEMACS 3.10/Amiga";
  234.     new_win.Flags = WINDOWCLOSE | SMART_REFRESH | ACTIVATE |
  235.         WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING | SIZEBRIGHT |
  236.         RMBTRAP | NOCAREREFRESH;
  237.     new_win.IDCMPFlags = CLOSEWINDOW | NEWSIZE | MOUSEBUTTONS |
  238.         RAWKEY;
  239.     new_win.Type = WBENCHSCREEN;
  240.     new_win.FirstGadget = NULL;
  241.     new_win.CheckMark = NULL;
  242.     new_win.Screen = NULL;
  243.     new_win.BitMap = NULL;
  244.     new_win.MinWidth = 100;
  245.     new_win.MinHeight = 25;
  246.     new_win.MaxWidth = 640;
  247.     new_win.MaxHeight = 200;
  248.  
  249.     /* open the window! */
  250.     win = (struct Window *)OpenWindow(&new_win);
  251.     if (win == NULL) {
  252.         printf("%%Can not open a window\n");
  253.         exit(-2);
  254.     }
  255.  
  256.     /* and open up the console for output */
  257.     con.io_Data = (APTR)win;
  258.     OpenDevice("console.device", 0, &con, 0);
  259.  
  260.     /* and init all the keyboard flags */
  261.     r_shiftflag = FALSE;
  262.     l_shiftflag = FALSE;
  263.     r_altflag = FALSE;
  264.     l_altflag = FALSE;
  265.     r_amiflag = FALSE;
  266.     l_amiflag = FALSE;
  267.     ctrlflag = FALSE;
  268.     lockflag = FALSE;
  269.  
  270.     /* initialize our private event queue */
  271.     in_init();
  272.  
  273.     /* set the current sizes */
  274.     newwidth(TRUE, 77);
  275.     newsize(TRUE, 23);
  276.  
  277.     /* on all screens we are not sure of the initial position
  278.        of the cursor                    */
  279.     ttrow = 999;
  280.     ttcol = 999;
  281. }
  282.  
  283. /*
  284.  * This function gets called just before we go back home to the command
  285.  * interpreter. On VMS it puts the terminal back in a reasonable state.
  286.  * Another no-operation on CPM.
  287.  */
  288. ttclose()
  289.  
  290. {
  291.     /* make sure there is no pending output */
  292.     ttflush();
  293.  
  294.     /* and now close up shop */
  295.     CloseDevice(&con);
  296.     CloseWindow(win);
  297.     OpenWorkBench();
  298. }
  299.  
  300. /*
  301.  * Write a character to the display. On VMS, terminal output is buffered, and
  302.  * we just put the characters in the big array, after checking for overflow.
  303.  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
  304.  * MS-DOS (use the very very raw console output routine).
  305.  */
  306.  
  307. ttputc(c)
  308.  
  309. char c;
  310.  
  311. {
  312.     /* add the character to the output buffer */
  313.         out_buf[out_ptr++] = c;
  314.  
  315.         /* send the buffer out if we are at the limit */
  316.         if (out_ptr >= OBUFSIZE)
  317.                 ttflush();
  318. }
  319.  
  320. /*
  321.  * Flush terminal buffer. Does real work where the terminal output is buffered
  322.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  323.  */
  324.  
  325. ttflush()
  326.  
  327. {
  328.     /* if there are any characters waiting to display... */
  329.         if (out_ptr) {
  330.             out_buf[out_ptr] = 0;    /* terminate the buffer string */
  331.             sendcon(out_buf);    /* send them out */
  332.             out_ptr = 0;        /* and reset the buffer */
  333.     }
  334. }
  335.  
  336. /*
  337.  * Read a character from the terminal.
  338.  */
  339.  
  340. ttgetc()
  341.  
  342. {
  343.     /* make sure there is no pending output */
  344. nxtchr:    ttflush();
  345.  
  346.     /* if it is already buffered up, get it */
  347.     if (in_check())
  348.         return(in_get());
  349.  
  350.     /* process an INTUITION event (possibly loading the input buffer) */
  351.     doevent();
  352.     goto nxtchr;
  353. }
  354.  
  355. #if    TYPEAH
  356. /* typahead:    Check to see if any characters are already in the
  357.         keyboard buffer
  358. */
  359.  
  360. typahead()
  361.  
  362. {
  363. tcheck:    /* if type ahead is already pending... */
  364.     if (in_check())
  365.         return(TRUE);
  366.  
  367.     /* check the signal for IDCMP events pending */
  368.     if ((1 << win->UserPort->mp_SigBit) != 0)
  369.         return(TRUE);
  370.  
  371.     /* no event in queue... no typeahead ready */
  372.     return(FALSE);
  373. }
  374. #endif
  375.  
  376. doevent()
  377.  
  378. {
  379.     register int eventX, eventY;    /* local copies of the event info */
  380.     struct IntuiMessage *event;    /* current event to repond to */
  381.     ULONG class;    /* class of event */
  382.     USHORT code;    /* data code */
  383.     SHORT x,y;    /* mouse x/y position at time of event */
  384.     char buf[128];    /*temp buff*/
  385.  
  386.     /* wait for an event to occur */
  387.     Wait(1 << win->UserPort->mp_SigBit);
  388.  
  389.     /* get the event and parse it up */
  390.     while (event = GetMsg(win->UserPort)) {
  391.         class = event->Class;
  392.         code = event->Code;
  393.         eventX = event->MouseX;
  394.         eventY = event->MouseY;
  395.         ReplyMsg(event);
  396.  
  397.         /* a normal keystroke? */
  398.         if (class == RAWKEY) {
  399.             dokey(code);
  400.             continue;
  401.         }
  402.  
  403.         /* User clicked on the close gadget! */
  404.         if (class == CLOSEWINDOW) {
  405.             quit(FALSE, 0);
  406.             stuffibuf(255, 0, 0);    /* fake a char to force quit to work */
  407.         }
  408.  
  409.         /* resolve the mouse address (border adjusted) */
  410.         if (class == NEWSIZE) {
  411.             x = (win->Width - 5) / CRWIDTH;
  412.             y = (win->Height - 10) / CRHEIGHT;
  413.         } else {
  414.             x = (eventX - 5) / CRWIDTH;
  415.             y = (eventY - 10) / CRHEIGHT;
  416.         }
  417.         if (x > 77)
  418.             x = 77;
  419.         if (y > 23)
  420.             y = 23;
  421.  
  422.         /* are we resizing the window? */
  423.         if (class == NEWSIZE) {
  424.             stuffibuf(MOUS | '1', x, y);
  425.             continue;
  426.         }
  427.  
  428.         /* and lastly, a mouse button press */
  429.         switch (code) {
  430.             case 104:    stuffibuf(MOUS | mod('a'), x, y);
  431.                     break;
  432.             case 232:    stuffibuf(MOUS | mod('b'), x, y);
  433.                     break;
  434.             case 105:    stuffibuf(MOUS | mod('e'), x, y);
  435.                     break;
  436.             case 233:    stuffibuf(MOUS | mod('f'), x, y);
  437.                     break;
  438.         }
  439.     }
  440.     return;
  441. }
  442.  
  443. int mod(c)    /* modify a character by the current shift and control flags */
  444.  
  445. int c;        /* original character */
  446.  
  447. {
  448.     /* first apply the shift and control modifiers */
  449.     if (l_shiftflag || r_shiftflag || lockflag)
  450.         c -= 32;
  451.     if (ctrlflag)
  452.         c |= CTRL;
  453.     return(c);
  454. }
  455.  
  456. sendcon(buf)    /* send a string to the console */
  457.  
  458. char *buf;    /* buffer to write out */
  459.  
  460. {
  461.     /* initialize the IO request */
  462.     con.io_Data = (APTR)buf;
  463.     con.io_Length = strlen(buf);
  464.     con.io_Command = CMD_WRITE;
  465.  
  466.     /* and perform the I/O */
  467.     SendIO(&con);
  468. }
  469.  
  470.  
  471. /* process an incomming keyboard code */
  472.  
  473. dokey(code)
  474.  
  475. int code;    /* raw keycode to convert */
  476.  
  477. {
  478.     register int ekey;    /* translate emacs key */
  479.     register int dir;    /* key direction (up/down) */
  480.     char buf[NSTRING];
  481.  
  482.     /* decode the direction of the key */
  483.     dir = TRUE;
  484.     if (code > 127) {
  485.         code = code & 127;
  486.         dir = FALSE;
  487.     }
  488.  
  489.     /* process various shift keys */
  490.     if (code >= 0x60) {
  491.         switch (code) {
  492.  
  493.             case 0x60:    l_shiftflag = dir;    break;
  494.             case 0x61:    r_shiftflag = dir;    break;
  495.             case 0x62:    lockflag    = dir;    break;
  496.             case 0x63:    ctrlflag    = dir;    break;
  497.             case 0x64:    l_altflag   = dir;    break;
  498.             case 0x65:    r_altflag   = dir;    break;
  499.             case 0x66:    l_amiflag   = dir;    break;
  500.             case 0x67:    r_amiflag   = dir;    break;
  501.  
  502.         }
  503.         return;
  504.     }
  505.  
  506.     /* up keystrokes are ignored for the rest of these */
  507.     if (dir == FALSE)
  508.         return;
  509.  
  510.     /* first apply the shift and control modifiers */
  511.     if (ctrlflag)
  512.         ekey = keytrans[code].rw_ccode;
  513.     else if (l_shiftflag || r_shiftflag || lockflag)
  514.         ekey = keytrans[code].rw_scode;
  515.     else
  516.         ekey = keytrans[code].rw_code;
  517.  
  518.     /* now apply the ALTD modifier */
  519.     if (r_altflag || l_altflag)
  520.         ekey |= ALTD;
  521.  
  522.     /* apply the META prefix */
  523.     if (r_amiflag || l_amiflag) {
  524.         if ('a' <= ekey && ekey <= 'z')
  525.             ekey -= 32;
  526.         ekey |= META;
  527.     }
  528.  
  529.     /* and place it in the input buffer */
  530.     stuffibuf(ekey, 0, 0);
  531. }
  532.  
  533. stuffibuf(key, x, y)    /* stuff a key in the input buffer */
  534.  
  535. int key;    /* extended keystroke to remember */
  536. int x, y;    /* mouse position to record */
  537.  
  538. {
  539.     register int upper;    /* upper extended bits of key */
  540.  
  541.     /* split the extended keystroke */
  542.     upper = key >> 8;
  543.     key = key & 255;
  544.  
  545.     /* if it is JUST control... encode it in! */
  546.     if (upper == (CTRL >> 8)) {
  547.         in_put(key - 64);
  548.         return;
  549.     }
  550.  
  551.     /* if it is normal, just place it inqueue */
  552.     if (upper == 0) {
  553.         in_put(key);
  554.         return;
  555.     }
  556.  
  557.     /* queue up an extended escape sequence */
  558.     in_put(0);        /* escape indicator */
  559.     in_put(upper);        /* event type */
  560.     if (upper & (MOUS >> 8)) {
  561.         in_put(x);    /* x position */
  562.         in_put(y);    /* y position */
  563.     }
  564.     in_put(key);        /* event code */
  565.     return;
  566. }
  567.  
  568. /*
  569.  * Create a subjob with a copy of the command intrepreter in it. When the
  570.  * command interpreter exits, mark the screen as garbage so that you do a full
  571.  * repaint. Bound to "^X C". The message at the start in VMS puts out a newline.
  572.  * Under some (unknown) condition, you don't get one free when DCL starts up.
  573.  */
  574. spawncli(f, n)
  575. {
  576.         long newcli;
  577.  
  578.     /* don't allow this command if restricted */
  579.     if (restflag)
  580.         return(resterr());
  581.  
  582.         mlwrite(TEXT1);
  583. /*              "[Starting new CLI]" */
  584.         sgarbf = TRUE;
  585.         Execute("NEWCLI \"CON:0/0/640/200/MicroEMACS Subprocess\"", 0L, 0L);
  586.         return(TRUE);
  587. }
  588.  
  589. /*
  590.  * Run a one-liner in a subjob. When the command returns, wait for a single
  591.  * character to be typed, then mark the screen as garbage so a full repaint is
  592.  * done. Bound to "C-X !".
  593.  */
  594. spawn(f, n)
  595. {
  596.         register int    s;
  597.         char            line[NLINE];
  598.  
  599.         long newcli;
  600.  
  601.     /* don't allow this command if restricted */
  602.     if (restflag)
  603.         return(resterr());
  604.  
  605.         if ((s=mlreply("!", line, NLINE)) != TRUE)
  606.                 return (s);
  607.         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
  608.         Execute(line, 0L, newcli);
  609.         Close(newcli);
  610.         tgetc();     /* Pause.               */
  611.         sgarbf = TRUE;
  612.         return(TRUE);
  613. }
  614.  
  615. /*
  616.  * Run an external program with arguments. When it returns, wait for a single
  617.  * character to be typed, then mark the screen as garbage so a full repaint is
  618.  * done. Bound to "C-X $".
  619.  */
  620.  
  621. execprg(f, n)
  622.  
  623. {
  624.         register int    s;
  625.         char            line[NLINE];
  626.  
  627.         long newcli;
  628.  
  629.     /* don't allow this command if restricted */
  630.     if (restflag)
  631.         return(resterr());
  632.  
  633.         if ((s=mlreply("!", line, NLINE)) != TRUE)
  634.                 return (s);
  635.         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
  636.         Execute(line, 0L, newcli);
  637.         Close(newcli);
  638.         tgetc();     /* Pause.               */
  639.         sgarbf = TRUE;
  640.         return(TRUE);
  641. }
  642.  
  643. /*
  644.  * Pipe a one line command into a window
  645.  * Bound to ^X @
  646.  */
  647. pipecmd(f, n)
  648. {
  649.         register int    s;    /* return status from CLI */
  650.     register WINDOW *wp;    /* pointer to new window */
  651.     register BUFFER *bp;    /* pointer to buffer to zot */
  652.         char    line[NLINE];    /* command line send to shell */
  653.     static char bname[] = "command";
  654.  
  655.     static char filnam[] = "ram:command";
  656.         long newcli;
  657.  
  658.     /* don't allow this command if restricted */
  659.     if (restflag)
  660.         return(resterr());
  661.  
  662.     /* get the command to pipe in */
  663.         if ((s=mlreply("@", line, NLINE)) != TRUE)
  664.                 return(s);
  665.  
  666.     /* get rid of the command output buffer if it exists */
  667.         if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
  668.         /* try to make sure we are off screen */
  669.         wp = wheadp;
  670.         while (wp != NULL) {
  671.             if (wp->w_bufp == bp) {
  672.                 onlywind(FALSE, 1);
  673.                 break;
  674.             }
  675.             wp = wp->w_wndp;
  676.         }
  677.         if (zotbuf(bp) != TRUE)
  678.  
  679.             return(FALSE);
  680.     }
  681.  
  682.         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
  683.     strcat(line, " >");
  684.     strcat(line, filnam);
  685.         Execute(line, 0L, newcli);
  686.     s = TRUE;
  687.         Close(newcli);
  688.         sgarbf = TRUE;
  689.  
  690.     if (s != TRUE)
  691.         return(s);
  692.  
  693.     /* split the current window to make room for the command output */
  694.     if (splitwind(FALSE, 1) == FALSE)
  695.             return(FALSE);
  696.  
  697.     /* and read the stuff in */
  698.     if (getfile(filnam, FALSE) == FALSE)
  699.         return(FALSE);
  700.  
  701.     /* make this window in VIEW mode, update all mode lines */
  702.     curwp->w_bufp->b_mode |= MDVIEW;
  703.     wp = wheadp;
  704.     while (wp != NULL) {
  705.         wp->w_flag |= WFMODE;
  706.         wp = wp->w_wndp;
  707.     }
  708.  
  709.     /* and get rid of the temporary file */
  710.     unlink(filnam);
  711.     return(TRUE);
  712. }
  713.  
  714. /*
  715.  * filter a buffer through an external DOS program
  716.  * Bound to ^X #
  717.  */
  718. filter(f, n)
  719.  
  720. {
  721.         register int    s;    /* return status from CLI */
  722.     register BUFFER *bp;    /* pointer to buffer to zot */
  723.         char line[NLINE];    /* command line send to shell */
  724.     char tmpnam[NFILEN];    /* place to store real file name */
  725.     static char bname1[] = "fltinp";
  726.  
  727.     static char filnam1[] = "ram:fltinp";
  728.     static char filnam2[] = "ram:fltout";
  729.         long newcli;
  730.  
  731.     /* don't allow this command if restricted */
  732.     if (restflag)
  733.         return(resterr());
  734.  
  735.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  736.         return(rdonly());    /* we are in read only mode    */
  737.  
  738.     /* get the filter name and its args */
  739.         if ((s=mlreply("#", line, NLINE)) != TRUE)
  740.                 return(s);
  741.  
  742.     /* setup the proper file names */
  743.     bp = curbp;
  744.     strcpy(tmpnam, bp->b_fname);    /* save the original name */
  745.     strcpy(bp->b_fname, bname1);    /* set it to our new one */
  746.  
  747.     /* write it out, checking for errors */
  748.     if (writeout(filnam1) != TRUE) {
  749.         mlwrite(TEXT2);
  750. /*                      "[Cannot write filter file]" */
  751.         strcpy(bp->b_fname, tmpnam);
  752.         return(FALSE);
  753.     }
  754.  
  755.         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
  756.     strcat(line, " <ram:fltinp >ram:fltout");
  757.         Execute(line,0L,newcli);
  758.     s = TRUE;
  759.         Close(newcli);
  760.         sgarbf = TRUE;
  761.  
  762.     /* on failure, escape gracefully */
  763.     if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
  764.         mlwrite(TEXT3);
  765. /*                      "[Execution failed]" */
  766.         strcpy(bp->b_fname, tmpnam);
  767.         unlink(filnam1);
  768.         unlink(filnam2);
  769.         return(s);
  770.     }
  771.  
  772.     /* reset file name */
  773.     strcpy(bp->b_fname, tmpnam);    /* restore name */
  774.     bp->b_flag |= BFCHG;        /* flag it as changed */
  775.  
  776.     /* and get rid of the temporary file */
  777.     unlink(filnam1);
  778.     unlink(filnam2);
  779.     return(TRUE);
  780. }
  781.  
  782. /* return a system dependant string with the current time */
  783.  
  784. char *PASCAL NEAR timeset()
  785.  
  786. {
  787.     return(errorm);
  788. }
  789.  
  790. #if    COMPLET && AZTEC
  791. /*    FILE Directory routines        */
  792.  
  793. char path[NFILEN];    /* path of file to find */
  794. char rbuf[NFILEN];    /* return file buffer */
  795. extern char *scdir();
  796.  
  797. /*    do a wild card directory search (for file name completion) */
  798.  
  799. char *PASCAL NEAR getffile(fspec)
  800.  
  801. char *fspec;    /* pattern to match */
  802.  
  803. {
  804.     register int index;        /* index into various strings */
  805.     char fname[NFILEN];        /* file/path for DOS call */
  806.  
  807.     /* first parse the file path off the file spec */
  808.     strcpy(path, fspec);
  809.     index = strlen(path) - 1;
  810.     while (index >= 0 && (path[index] != '/' &&
  811.                 path[index] != '\\' && path[index] != ':'))
  812.         --index;
  813.     path[index+1] = 0;
  814.  
  815.     /* construct the composite wild card spec */
  816.     strcpy(fname, path);
  817.     strcat(fname, &fspec[index+1]);
  818.     strcat(fname, "*.*");
  819.  
  820.     /* save the path/wildcard off */
  821.     strcpy(path, fname);
  822.  
  823.     /* and call for the first file */
  824.     return(getnfile());
  825. }
  826.  
  827. char *PASCAL NEAR getnfile()
  828.  
  829. {
  830.     register char *sp;    /* return from scdir */
  831.  
  832.     /* and call for the next file */
  833.     sp = scdir(path);
  834.     if (sp == NULL)
  835.         return(NULL);
  836.  
  837.     /* return the next file name! */
  838.     strcpy(rbuf, sp);
  839.     return(rbuf);
  840. }
  841. #else
  842. char *PASCAL NEAR getffile(fspec)
  843.  
  844. char *fspec;    /* file to match */
  845.  
  846. {
  847.     return(NULL);
  848. }
  849.  
  850. char *PASCAL NEAR getnfile()
  851.  
  852. {
  853.     return(NULL);
  854. }
  855. #endif
  856. #else
  857. adoshello()
  858. {
  859. }
  860. #endif
  861.